#ifndef __M__CONSUMER_H_
#define __M__CONSUMER_H_

#include "../mqCommon/Helper.hpp"
#include "../mqCommon/Logger.hpp"
#include "../mqCommon/proto/mq_message.pb.h"
#include <iostream>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <vector>
#include <functional>

using namespace mq_message;
using namespace mq;
using namespace std;

namespace mq
{
    class QueueConsumer;
    using ConsumerCallback = function<void(const string &, const BasicProperties *, const string &)>; // 消息处理回调函数

    // 消费者类：当一个用户订阅了一个队列的消息，就算创建了一个消费者
    struct Consumer
    {
        using ptr = shared_ptr<Consumer>;
        string _tag;                // 消费者标识
        string _qname;              // 订阅的队列名
        bool _auto_ack;             // 自动应答标志
        ConsumerCallback _callback; // 消息处理回调函数：当队列有消息，按序获取到一个消费者，调用该消费者的消息处理回调
        // 便自动找到该消费者对应的信道和连接，将消息属性+body进行发送
        Consumer(const string &tag, const string &qname, bool auto_ack, const ConsumerCallback &callback)
            : _tag(tag), _qname(qname), _auto_ack(auto_ack), _callback(callback) {}
        Consumer() {}
    };

    /*
    队列消费者管理类：以队列为单元，管理订阅了该队列的消费者
    操作：
        1.新增消费者：用户订阅该队列
        2.删除消费者：用户取消订阅/信道关闭/连接关闭
        3.获取消费者：RR轮转，按序获取，负载均衡

    元素：
        1.队列名
        2.队列消费者管理结构vector
        3.轮转序号
        4.互斥锁
    */
    class QueueConsumer
    {
    public:
        using ptr = shared_ptr<QueueConsumer>;
        QueueConsumer(const string &qname) : _qname(qname) ,_rr_seq(0){}
        Consumer::ptr create(const string &tag, bool auto_ack, const ConsumerCallback &callback) // 创建一个订阅了该队列的消费者
        {
            unique_lock<mutex> lock(mtx);
            // 1.判断消费者是否存在
            for (auto &consumer : _consumers)
            {
                if (consumer->_tag == tag)
                    return consumer;
            }
            // 2.构造消费者对象
            auto consumer = make_shared<Consumer>(tag, _qname, auto_ack, callback);
            // 3.添加管理
            _consumers.push_back(consumer);
            return consumer;
        }
        void remove(const string &ctag) // 删除消费者
        {
            unique_lock<mutex> lock(mtx);
            // 遍历查找并删除
            for (auto it = _consumers.begin(); it != _consumers.end(); it++)
            {
                if ((*it)->_tag == ctag)
                {
                    _consumers.erase(it);
                    return;
                }
            }
        }
        bool exists(const string &ctag) // 该消费者是否订阅该队列
        {
            unique_lock<mutex> lock(mtx);
            for (auto &consumer : _consumers)
            {
                if (consumer->_tag == ctag)
                    return true;
            }
            return false;
        }
        Consumer::ptr choose() // 按序获取一个消费者
        {
            unique_lock<mutex> lock(mtx);
            if (_consumers.size() == 0) // 订阅该队列的消费者数量为0，无法获取
            {
                DLOG("该队列没有消费者订阅，获取失败：%s", _qname.c_str());
                return Consumer::ptr();
            }
            Consumer::ptr consumer = _consumers[_rr_seq++];
            if(consumer==Consumer::ptr())
            {
            }
            if (_rr_seq >= _consumers.size())
                _rr_seq %= _consumers.size();
            
            return consumer;
        }
        bool empty() // 该队列是否有消费者订阅
        {
            unique_lock<mutex> lock(mtx);
            return _consumers.size() == 0;
        }
        void clear() // 删除队列时，删除该队列关联的所有消费者数据
        {
            unique_lock<mutex> lock(mtx);
            _consumers.clear();
            _rr_seq = 0;
        }

    private:
        mutex mtx;                        // 互斥锁
        string _qname;                    // 队列名
        uint64_t _rr_seq;                 // 轮转序号
        vector<Consumer::ptr> _consumers; // 队列消费者管理结构vector
    };

    /*  消费者管理模块：管理所有队列的订阅消费者
        操作：
            1.队列消费者管理的初始化/删除
            2.提供队列消费者的功能：对指定队列的消费者增删查
            3.删除所有队列消费者结构
    */
    class ConsumerManager
    {
    public:
        using ptr = shared_ptr<ConsumerManager>;
        ConsumerManager() {}
        void initQueueConsumer(const string &qname) // 初始化队列消费者结构
        {
            unique_lock<mutex> lock(mtx);
            // 1.存在判断
            auto it = _qcmap.find(qname);
            if (it != _qcmap.end())
                return;
            // 2.构造队列消费者管理对象并添加管理
            auto qconsumer = make_shared<QueueConsumer>(qname);
            _qcmap.insert(make_pair(qname, qconsumer));
        }
        void destroyQueueConsumer(const string &qname) // 删除队列消费者结构
        {
            unique_lock<mutex> lock(mtx);
            // auto it = _qcmap.find(qname);
            // if (it == _qcmap.end())
            //     return;
            // auto qconsumer = it->second;
            // qconsumer->clear();
            _qcmap.erase(qname);
        }
        Consumer::ptr create(const string &qname, const string &tag, bool auto_ack, const ConsumerCallback &callback) // 向指定队列新增消费者
        {
            QueueConsumer::ptr qc;
            {
                unique_lock<mutex> lock(mtx);
                // 1.存在判断
                auto it = _qcmap.find(qname);
                if (it == _qcmap.end())
                {
                    DLOG("未找到队列，无法创建消费者： %s create %s", qname.c_str(), tag.c_str());
                    return Consumer::ptr();
                }
                // 2.获取指定队列
                qc = it->second;
            }
            // 3.新增消费者
            return qc->create(tag, auto_ack, callback);
        }
        void remove(const string &qname, const string &ctag) // 移除指定队列的指定消费者
        {
            QueueConsumer::ptr qc;
            {
                unique_lock<mutex> lock(mtx);
                // 1.存在判断
                auto it = _qcmap.find(qname);
                if (it == _qcmap.end())
                {
                    DLOG("未找到队列，无法移除消费者： %s create %s", qname.c_str(), ctag.c_str());
                    return;
                }
                // 2.获取指定队列
                qc = it->second;
            }
            // 3.移除指定消费者
            qc->remove(ctag);
        }
        Consumer::ptr choose(const string &qname) // 获取指定队列的消费者（按序）
        {
            QueueConsumer::ptr qc;
            {
                unique_lock<mutex> lock(mtx);
                // 1.存在判断
                auto it = _qcmap.find(qname);
                if (it == _qcmap.end())
                {
                    DLOG("未找到队列，无法获取消费者： %s", qname.c_str());
                    return Consumer::ptr();
                }
                // 2.获取指定队列
                qc = it->second;
            }
            // 3.获取消费者
            
            return qc->choose();
        }
        void clear()
        {
            unique_lock<mutex> lock(mtx);
            _qcmap.clear();
        }

        // test:
        bool empty(const string &qname) // 判断指定队列是否有消费者订阅
        {
            QueueConsumer::ptr qc;
            {
                unique_lock<mutex> lock(mtx);
                // 1.存在判断
                auto it = _qcmap.find(qname);
                if (it == _qcmap.end())
                {
                    DLOG("未找到队列，无法判断该队列是否有消费者订阅： %s", qname.c_str());
                    return false;
                }
                // 2.获取指定队列
                qc = it->second;
            }
            // 3.判断
            return qc->empty();
        }
        bool exists(const string &qname, const string &ctag) // 判断指定队列是否有指定消费者订阅
        {
            QueueConsumer::ptr qc;
            {
                unique_lock<mutex> lock(mtx);
                // 1.存在判断
                auto it = _qcmap.find(qname);
                if (it == _qcmap.end())
                {
                    DLOG("未找到队列，无法判断该队列是否有消费者订阅： %s", qname.c_str());
                    return false;
                }
                // 2.获取指定队列
                qc = it->second;
            }
            // 3.判断
            return qc->exists(ctag);
        }

    private:
        mutex mtx;                                        // 保护_qcmap
        unordered_map<string, QueueConsumer::ptr> _qcmap; // 队列名：队列消费者管理句柄
    };
}
#endif